package com.weilive.core.utils.ini;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

public class IniToBeanUtils {
	private static final Logger logger = LoggerFactory
			.getLogger(IniToBeanUtils.class);

	// ini文件转化成map
	public static final <K, V> Map<K, V> toMap(String iniPath,
			Class<K> keyClazz, Class<V> valueClazz,
			Map<String, String> overrideKeyMapper) {
		return toMap(iniPath, "id", keyClazz, valueClazz, overrideKeyMapper);
	}

	public static final <K, V> Map<K, V> toMap(String iniPath, String keyProp,
			Class<K> keyClazz, Class<V> valueClazz,
			Map<String, String> overrideKeyMapper) {
		Ini ini = new Ini(iniPath);
		if (!ini.loadIniFile()) {
			logger.error("初始化{}出现错误", iniPath);
			return Collections.emptyMap();
		}
		return toMap(ini, keyProp, keyClazz, valueClazz, overrideKeyMapper);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static final <K, V> Map<K, V> toMap(Ini ini, String keyProp,
			Class<K> keyClazz, Class<V> valueClazz,
			Map<String, String> overrideKeyMapper) {
		keyProp = calcPropertyName(keyProp);

		Map<String, String> keyMap = wrapOverrideKeyMap(overrideKeyMapper);

		Map map = new HashMap();

		for (int i = 0; i < ini.getSectionCount(); i++) {
			Map<String, String> beanMap = sectionToMap(ini, i, keyMap);
			if (Map.class.isAssignableFrom(valueClazz))
				map.put(ConvertUtils.convert((String) beanMap.get(keyProp),
						keyClazz), beanMap);
			else {
				try {
					Object bean = valueClazz.newInstance();
					BeanUtils.populate(bean, beanMap);
					map.put(ConvertUtils.convert((String) beanMap.get(keyProp),
							keyClazz), bean);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return map;
	}

	// Map<K, Map> 转化成Map<K, Bean>形式
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static final <K, V> Map<K, V> originalMap2BeanMap(
			Map<K, Map> originalMap, Class<V> beanClazz) {
		Map map = new HashMap();
		for (Map.Entry entry : originalMap.entrySet()) {
			try {
				Object bean = beanClazz.newInstance();
				BeanUtils.populate(bean, (Map) entry.getValue());
				map.put(entry.getKey(), bean);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return map;
	}

	// ini　转化成set形式
	public static final <T> Set<T> toSet(String iniPath, Class<T> elementClazz,
			String keyName) {
		Ini ini = new Ini(iniPath);
		if (!ini.loadIniFile()) {
			logger.error("初始化{}出现错误", iniPath);
			return Collections.emptySet();
		}
		return toSet(ini, elementClazz, keyName);
	}

	@SuppressWarnings("unchecked")
	private static final <T> Set<T> toSet(Ini ini, Class<T> elementClazz,
			String keyName) {
		Set<T> beanSet = new HashSet<T>();
		for (int i = 0; i < ini.getSectionCount(); i++) {
			Object e = ConvertUtils.convert(ini.getKeyValue(i, keyName, ""),
					elementClazz);

			beanSet.add((T) e);
		}
		return beanSet;
	}

	// 转化成list
	public static final <T> List<T> toList(String iniPath, Class<T> beanClazz,
			Map<String, String> overrideKeyMapper) {
		Ini ini = new Ini(iniPath);
		if (!ini.loadIniFile()) {
			logger.error("初始化{}出现错误", iniPath);
			return Collections.emptyList();
		}
		return toList(ini, beanClazz, overrideKeyMapper);
	}

	@SuppressWarnings("unchecked")
	public static final <T> List<T> toList(Ini ini, Class<T> beanClazz,
			Map<String, String> overrideKeyMapper) {
		List<T> beanList = new ArrayList<T>();

		Map<String, String> keyMap = wrapOverrideKeyMap(overrideKeyMapper);

		for (int i = 0; i < ini.getSectionCount(); i++) {
			Map<String, String> beanMap = sectionToMap(ini, i, keyMap);
			try {
				Object bean = beanClazz.newInstance();
				BeanUtils.populate(bean, beanMap);
				beanList.add((T) bean);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return beanList;
	}

	public static final <T> T toBean(String iniPath, Class<T> beanClazz,
			Map<String, String> overrideKeyMapper) {
		Ini ini = new Ini(iniPath);
		if (!ini.loadIniFile()) {
			logger.error("初始化{}出现错误", iniPath);
			return null;
		}
		return toBean(ini, beanClazz, overrideKeyMapper);
	}

	private static final <T> T toBean(Ini ini, Class<T> beanClazz,
			Map<String, String> overriderKeyMapper) {
		List<T> list = toList(ini, beanClazz, overriderKeyMapper);
		return (T) (CollectionUtils.isEmpty(list) ? null : list.get(0));
	}

	public static String calcPropertyName(String keyName) {
		return keyName.substring(0, 1).toLowerCase() + keyName.substring(1);
	}

	private static Map<String, String> wrapOverrideKeyMap(
			Map<String, String> overrideKeyMapper) {
		Map<String, String> keyMap = new HashMap<String, String>();
		if (overrideKeyMapper != null) {
			keyMap.putAll(overrideKeyMapper);
		}
		return keyMap;
	}

	private static Map<String, String> sectionToMap(Ini ini, int sectionIdx,
			Map<String, String> keyMap) {
		int keyCount = ini.getKeyCount(sectionIdx);
		Map<String, String> beanMap = new HashMap<String, String>();
		for (int j = 0; j < keyCount; j++) {
			String keyName = ini.getIndexKeyName(sectionIdx, j, "");
			String key = ini.getKeyValue(sectionIdx, j, "");
			if ((StringUtils.isEmpty(keyName)) || (StringUtils.isEmpty(key))) {
				continue;
			}

			if (!keyMap.containsKey(keyName)) {
				keyMap.put(keyName, calcPropertyName(keyName));
			}
			beanMap.put(keyMap.get(keyName), key);
		}
		return beanMap;
	}

	public static final <K, V> Map<K, V> toMapInMap(String iniPath,
			Class<K> keyClazz, Map<String, String> overrideKeyMapper) {
		return toMapInMap(iniPath, "id", keyClazz, overrideKeyMapper);
	}

	public static final <K, V> Map<K, V> toMapInMap(String iniPath,
			String keyProp, Class<K> keyClazz,
			Map<String, String> overrideKeyMapper) {
		Ini ini = new Ini(iniPath);
		if (!ini.loadIniFile()) {
			logger.error("初始化{}出现错误", iniPath);
			return Collections.emptyMap();
		}
		return toMapInMap(ini, keyProp, keyClazz, overrideKeyMapper);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static final <K, V> Map<K, V> toMapInMap(Ini ini, String keyProp,
			Class<K> keyClazz, Map<String, String> overrideKeyMapper) {
		Map<String, String> keyMap = wrapOverrideKeyMap(overrideKeyMapper);

		Map map = new HashMap();

		for (int i = 0; i < ini.getSectionCount(); i++) {
			Map<String, String> beanMap = sectionToMap(ini, i, keyMap);
			map.put(ConvertUtils.convert((String) beanMap.get(keyProp),
					keyClazz), beanMap);
		}
		return map;
	}
}